import Foundation
import CoreBluetooth

@objcMembers
public class BxOtaLibrary : NSObject{
    
    @objc var mCentralMgr: CBCentralManager!
    internal var initlallizer: DeviceInitializer!
    internal var delegate: OtaDelegate?
    private var inProgress = false
    
    // MARK: 单例
    private static let core:BxOtaLibrary = {
        let shared = BxOtaLibrary()
        return shared
    }()
    
    public override init() {
        super.init()
        initlallizer = DeviceInitializer()
    }
    
    public class func shared() -> BxOtaLibrary {
        return core
    }
    
    private func onDeviceCallback(result:Bool, errorMessage:String?){
        currentTaskIndex = -1
        if(result){
            self._ctrl = initlallizer._ctrl
            self._data = initlallizer._data
            self.target = initlallizer.peripheral
            self.execute()
        }else{
            print(errorMessage ?? "Not Found Peripheral")
            self.inProgress = false
            self.delegate?.onInitialError(error: errorMessage ?? "Unknown Error")
        }
    }
    
    private var target:CBPeripheral?
    private var _ctrl:CBCharacteristic?
    private var _data:CBCharacteristic?
    @objc private var tasks = [BxOtaTask]()//remove
    private var fastMode = false
    private var currentTaskIndex = -1;
    private var basicProcess:BasicProcess?
    private var lock = NSLock()
    
    
    //递归
    private func execute(){
        currentTaskIndex += 1
        if(currentTaskIndex < tasks.count){
            let otaTask = self.tasks[currentTaskIndex]
            self.basicProcess = BasicProcess(
                peripheral: self.target!,
                ctrl: _ctrl!,
                data: _data!,
                index: currentTaskIndex,
                task: otaTask,
                fastMode: self.fastMode
            )
            self.basicProcess?.start(self.onOtaStateUpdated)
        }else{
            finish()
        }
    }
    
    private func finish(){
        if(fastMode){
            rebootPeripheral()
        }
        self.inProgress = false
        delegate?.onFinish()
    }
    
    private func rebootPeripheral(){
        var cmd = Data()
        cmd.append(UInt8(0x0B))
        self.target?.writeValue(cmd, for: self._ctrl!, type: .withResponse)
    }
    
    func onOtaStateUpdated(_ otaState:OtaState){
        self.delegate?.onTaskStateChanged(state: otaState)
        if( otaState.endTime > 0 ){
            execute()
        }
    }
    
    //todo 注意防抖
    @objc public func startFastOta(identifier: UUID, tasks: [BxOtaTask], delegate: OtaDelegate?)->Bool{
        lock.lock()
        if(inProgress){
            lock.unlock()
            return false
        }else{
            self.tasks = tasks
            self.fastMode = true
            self.delegate = delegate
            self.inProgress = true
            initlallizer.findAndSetupPeripheral(identifier: identifier, callback: { (res,err) in
                self.lock.unlock()
                self.onDeviceCallback(result: res,errorMessage: err)
            })
            return true
        }
    }
    
    public  func startOta(identifier: UUID, task:BxOtaTask, delegate: OtaDelegate?)->Bool{
        if mCentralMgr.state != .poweredOn{
            return false
        }
        lock.lock()
        if(inProgress){
            lock.unlock()
            return false
        }else{
            self.tasks = [task]
            self.fastMode = false
            self.delegate = delegate
            self.inProgress = true
            initlallizer.findAndSetupPeripheral(identifier: identifier, callback: self.onDeviceCallback)
            lock.unlock()
            return true
        }
    }
}
